package com.tuni.birthdaymoney.web.controller;

import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.spec.InvalidKeySpecException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.tuni.birthdaymoney.persistence.entity.Person;
import com.tuni.birthdaymoney.persistence.entity.Role;
import com.tuni.birthdaymoney.persistence.entity.User;
import com.tuni.birthdaymoney.service.DepartmentService;
import com.tuni.birthdaymoney.service.PersonService;
import com.tuni.birthdaymoney.service.PositionService;
import com.tuni.birthdaymoney.service.UserService;
import com.tuni.birthdaymoney.service.util.web.DateTimeEditor;
import com.tuni.birthdaymoney.web.model.MasterPage;
import com.tuni.birthdaymoney.web.model.PersonDeleteConfirmationPage;
import com.tuni.birthdaymoney.web.model.PersonEditorPage;

@Controller
public class PersonEditorController {

    @Autowired
    private PersonService personService;
    @Autowired
    private UserService userService;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private PositionService positionService;

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        String dateFormat = "dd.MM.yyyy";
        binder.registerCustomEditor(DateTime.class, new DateTimeEditor(dateFormat, false));
    }

    @RequestMapping(value = "/staff/add", method = RequestMethod.GET)
    public String showAdd(Principal principal, Map<String, Object> personEditorPageMap) {
        User currentUser = userService.getUserByEmail(principal.getName());
        MasterPage masterPageModel = new MasterPage(currentUser, false);
        personEditorPageMap.put("masterPageModel", masterPageModel);
        if (userService.canAddStaff(currentUser)) {
            PersonEditorPage personEditorPageModel = new PersonEditorPage();
            personEditorPageModel.setTitle("Create new profile");
            personEditorPageModel.setSubmitText("Create");
            personEditorPageModel.setFormAction("add");
            personEditorPageModel.setShowPasswordInput(true);
            Person person = new Person();
            // by default
            person.setWantToReceive(true);
            person.setWantToCelebrate(true);
            personEditorPageModel.setPerson(person);
            personEditorPageModel.setRole(new Role());
            personEditorPageModel.setPositions(positionService.findAll());
            personEditorPageModel.setDepartments(departmentService.findAll());
            personEditorPageMap.put("personEditorPageModel", personEditorPageModel);
            return "person_editor";
        }
        return "forbidden";
    }

    @RequestMapping(value = "/staff/add", method = RequestMethod.POST)
    public String submitAdd(@ModelAttribute("personEditorPageModel") PersonEditorPage personEditorPageModel, BindingResult result,
            HttpServletRequest request) {

        if (!result.hasErrors()) {
            if (personEditorPageModel.fileDataNotNullOrEmpty()) {
                uploadPhotoForPerson(personEditorPageModel, request);
            }
            if (personEditorPageModel.isSaveAsUser()) {
                try {
                    personService.addAsUser(personEditorPageModel.getPerson(), personEditorPageModel.getRole(),
                            personEditorPageModel.getPassword());
                } catch (NoSuchAlgorithmException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvalidKeySpecException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                personService.add(personEditorPageModel.getPerson());
            }
        }
        return "redirect:/staff.html";
    }

    @RequestMapping(value = "/staff/{personId}/remove", method = RequestMethod.GET)
    public String showDelete(Principal principal, Map<String, Object> personDeleteConfirmationPageMap,
            @PathVariable("personId") Integer personId) {
        User currentUser = userService.getUserByEmail(principal.getName());
        MasterPage masterPageModel = new MasterPage(currentUser, false);
        personDeleteConfirmationPageMap.put("masterPageModel", masterPageModel);
        if (userService.canDeleteStaff(currentUser)) {
            PersonDeleteConfirmationPage personDeleteConfirmationPageModel = new PersonDeleteConfirmationPage();
            personDeleteConfirmationPageModel.setPerson(personService.getById(personId));
            personDeleteConfirmationPageMap.put("personDeleteConfirmationPageModel", personDeleteConfirmationPageModel);
            return "person_delete_confirmation";
        }
        return "forbidden";
    }

    @RequestMapping(value = "/staff/{personId}/remove", method = RequestMethod.POST)
    public String submitDelete(Principal principal, @PathVariable("personId") Integer personId) {
        Person person = personService.getById(personId);
        person.setFired(true);
        personService.update(person);
        return "redirect:/staff.html";
    }

    @RequestMapping(value = "/staff/{personId}/update", method = RequestMethod.GET)
    public String showUpdate(Principal principal, Map<String, Object> personEditorPageMap, @PathVariable("personId") Integer personId) {
        User currentUser = userService.getUserByEmail(principal.getName());
        MasterPage masterPageModel = new MasterPage(currentUser, false);
        personEditorPageMap.put("masterPageModel", masterPageModel);
        if (userService.canUpdateStaff(currentUser)) {
            PersonEditorPage personEditorPageModel = new PersonEditorPage();
            personEditorPageModel.setTitle("Edit profile");
            personEditorPageModel.setFormAction(String.format("%s/update", personId));
            Person person = personService.getById(personId);

            if (person.isFired())
                personEditorPageModel.setSubmitText("Save and Hire");
            else
                personEditorPageModel.setSubmitText("Save");

            personEditorPageModel.setPerson(person);
            if (person.getUser() != null) {
                personEditorPageModel.setSaveAsUser(true);
                personEditorPageModel.setShowPasswordInput(false);
                personEditorPageModel.setRole(person.getUser().getRole());
            } else {
                personEditorPageModel.setShowPasswordInput(true);
                personEditorPageModel.setRole(new Role());
            }
            personEditorPageModel.setPositions(positionService.findAll());
            personEditorPageModel.setDepartments(departmentService.findAll());
            personEditorPageMap.put("personEditorPageModel", personEditorPageModel);
            return "person_editor";
        }
        return "forbidden";
    }

    @RequestMapping(value = "/staff/{personId}/update", method = RequestMethod.POST)
    public String submitUpdate(@ModelAttribute("personEditorPageModel") PersonEditorPage personEditorPageModel, BindingResult result,
            HttpServletRequest request) {
        if (!result.hasErrors()) {
            if (personEditorPageModel.fileDataNotNullOrEmpty()) {
                uploadPhotoForPerson(personEditorPageModel, request);
            }
            if (personEditorPageModel.isSaveAsUser()) {
                try {
                    personService.updateAsUser(personEditorPageModel.getPerson(), personEditorPageModel.getRole(),
                            personEditorPageModel.getPassword());
                } catch (NoSuchAlgorithmException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvalidKeySpecException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                personService.update(personEditorPageModel.getPerson());
            }
        }
        return "redirect:/staff.html";
    }

    private void uploadPhotoForPerson(PersonEditorPage personEditorPageModel, HttpServletRequest request) {
        String fileName = personEditorPageModel.getPerson().getLastName().toLowerCase() + ".jpg";
        File destination = new File(request.getSession().getServletContext().getRealPath("/static/img/photo/" + fileName));
        personEditorPageModel.getPerson().setPhotoPath(fileName);
        try {
            personEditorPageModel.getFileData().transferTo(destination);
        } catch (IllegalStateException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
